﻿
#include "tcp_conn.h"
#include <mutex>
#include "msg_queue.h"
#include "ZsLog.h"
#include "event_loop.h"

std::unique_ptr<zs::CTcpConn> zs::CTcpConn::instance_ = nullptr;

zs::CTcpConn::~CTcpConn()
{
    if (connected_)
    {
        socket_.close();
        connected_ = false;
    }
}

bool zs::CTcpConn::connect(const std::string &ip, int port)
{
    try
    {
        ip_ = ip;
        port_ = port;
        Poco::Net::SocketAddress serverAddress(ip, port); // 服务器地址
        socket_.connect(serverAddress); // 连接到服务器
        socket_.setBlocking(false); // 设置为非阻塞模式
        if (nullptr != event_loop_)
        {
            // 注册读事件处理器
            event_loop_->add_read_event_handler(socket_, get_read_callback());
            // 注册写事件处理器
            event_loop_->add_write_event_handler(socket_, get_write_callback());
        }
    }
    catch (Poco::Exception& e)
    {
        LOG_ERROR << "Failed to connect to server: " << e.displayText();
        return false;
    }
    return (connected_ = true);
}

zs::CTcpConn *zs::CTcpConn::get_instance()
{
    static std::once_flag flag;
    std::call_once(flag, [] { instance_.reset(new (std::nothrow)zs::CTcpConn); });
    return instance_.get();
}

void zs::CTcpConn::set_read_callback(zs::SkReadEventHandler callback)
{
    read_callback_ = std::move(callback);
}

void zs::CTcpConn::set_write_callback(zs::SkWriteEventHandler callback)
{
    write_callback_ = std::move(callback);
}

void zs::CTcpConn::set_error_callback(zs::SkErrorEventHandler callback)
{
    error_callback_ = std::move(callback);
}

void zs::CTcpConn::default_write_callback()
{
    std::string msg = zs::CMsgQueue::get_instance().pop_msg();
    if (msg.empty())
    {
        return;
    }
    try
    {
        size_t total_sent = 0;
        size_t len = msg.length();
        while (total_sent < len)
        {
            // 计算当前发送数据包的长度，可能是固定长度或者剩余数据长度的最小值
            size_t packet_len = std::min(fixed_packet_len_, len - total_sent);

            // 发送当前数据包
            int sent = socket_.sendBytes(msg.c_str() + total_sent, static_cast<int>(packet_len));
            if (sent == -1)
            {
                // 发送失败
                if (EAGAIN == errno || EWOULDBLOCK == errno)
                {
                    // 发送缓冲区已满
                    LOG_INFO << "send buffer is full";
                    Poco::Thread::sleep(600);
                    continue;
                }
                LOG_ERROR << "Error in sending data";
                break;
            }
             LOG_INFO << "send " << sent << " bytes data to server";

            total_sent += sent;
        }
        if (total_sent == len)
        {
            LOG_INFO << "send all data to server";
        }
    }
    catch (Poco::Exception& e)
    {
        LOG_ERROR << "Failed to send data to server: " << e.displayText();
        connected_ = false;
        LOG_INFO << "Reconnecting to server...";
        socket_.close();
        event_loop_->remove_event_read_handler(socket_);
        event_loop_->remove_event_write_handler(socket_);
    }
}

void zs::CTcpConn::default_read_callback(std::string& msg)
{
    // 处理套接字可读事件
    char buffer[4096] = {0};
    try
    {
        LOG_INFO << "receiveBytes";
        int n = socket_.receiveBytes(buffer, sizeof(buffer));
        if (n > 0)
        {
            LOG_INFO << "Received data from server: " << buffer;
            msg = buffer;
        }
        else if (n == 0)
        {
            LOG_ERROR << "Connection closed by server.";
        }
    }
    catch (Poco::Exception& e)
    {
        LOG_ERROR << "Error reading data from server: " << e.displayText();
        connected_ = false;
        LOG_INFO << "Reconnecting to server...";
        socket_.close();
        event_loop_->remove_event_read_handler(socket_);
        event_loop_->remove_event_write_handler(socket_);
    }
}

zs::SkWriteEventHandler zs::CTcpConn::get_write_callback()
{
    if (!write_callback_)
    {
        return [this] { default_write_callback(); };
    }
    return write_callback_;
}

zs::SkReadEventHandler zs::CTcpConn::get_read_callback()
{
    if (!read_callback_)
    {
        return [this](std::string& msg) { default_read_callback(msg); };
    }
    return read_callback_;
}

void zs::CTcpConn::set_event_loop(zs::CEventLoop *event_loop)
{
    event_loop_ = event_loop;
}


